from abc import ABC, abstractmethod
import numpy as np


class OptimizerBase(ABC):
    def __init__(self) -> None:
        pass

    @abstractmethod
    def update(self, param, grad, logo):
        pass

    def __call__(self, param, grad, logo):
        return self.update(param, grad, logo)


class AdaGrad(OptimizerBase):
    """
        AdaGrad method
        @params:
            lr:learing_rate,即学习率
    """

    def __init__(self, lr=0.01):
        self.learning_rate = lr
        self.grad_set = {}

    def update(self, param, grad, logo):
        if logo not in self.grad_set:
            self.grad_set[logo] = grad * grad
        else:
            self.grad_set[logo] += grad * grad
        param -= self.learning_rate * grad / \
            np.sqrt(self.grad_set[logo] + 1e-7)
        return param


class SGD(OptimizerBase):
    """
        SGD method，随机梯度下降法
        @params:
            lr:learing_rate,即学习率
    """

    def __init__(self, lr=0.01):
        self.lr = lr

    # 参数更新
    def update(self, param, grad, logo):
        param -= self.lr * grad
        return param
